﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using Support.IOC.Resources;
using ModelProject.Repositorios;
using ManagerProject.ClientesManagement;
using DataProject.Repositorios;
using DataProject;
using DataProject.UnitOfWork;
using Support.IOC.LifetimeManagers;
using Microsoft.Practices.Unity;
using ManagerProject.TiposDocumentosManagement;

namespace Support.IOC
{
    sealed class IOCUnityContainer : IIOCContainer
    {
        #region private fields

        private readonly IDictionary<string, IUnityContainer> _containerDictionary;

        #endregion

        #region constructor

        public IOCUnityContainer()
        {
            _containerDictionary = new Dictionary<string, IUnityContainer>();

            // Root container
            IUnityContainer rootContainer = new UnityContainer();
            _containerDictionary.Add("RootContext", rootContainer);

            // Real context container.
            IUnityContainer realContainer = rootContainer.CreateChildContainer();
            _containerDictionary.Add("RealContext", realContainer);

            ConfigureRootContainer(rootContainer);
            ConfigureRealContainer(realContainer);

            // Fake context container.
            // Added a crude error trap so that this doesn't break in environments where moles is not installed.
            // todo: Put a better performing check in here.
            try
            {
                IUnityContainer fakeContainer = rootContainer.CreateChildContainer();
                _containerDictionary.Add("FakeContext", fakeContainer);

                //ConfigureFakeContainer(fakeContainer);
            }
            catch (Exception) { }
        }

        #endregion

        #region IServiceFactory Members

        public TService Resolve<TService>()
        {
            IUnityContainer container = GetContainer();

            return container.Resolve<TService>();
        }

        public object Resolve(Type type)
        {
            IUnityContainer container = GetContainer();
            return container.Resolve(type, null);
        }

        public void RegisterType(Type type)
        {
            IUnityContainer container = _containerDictionary["RootContext"];

            if (container != null)
            {
                container.RegisterType(type, new TransientLifetimeManager());
            }
        }

        #endregion

        #region private methods

        private IUnityContainer GetContainer()
        {
            string containerName = ConfigurationManager.AppSettings["DefaultIoCContainer"];

            if (string.IsNullOrEmpty(containerName) || string.IsNullOrWhiteSpace(containerName))
            {
                // Value is not being retrieved from app.config correctly during Application tests
                // Temporarily commenting the exception and overriding until cause can be identified
                //throw new ArgumentNullException(Messages.DefaultIOCSettings);
                containerName = "FakeContext";
            }

            if (!_containerDictionary.ContainsKey(containerName))
            {
                throw new InvalidOperationException(Messages.ContainerCannotBeFound);
            }

            return _containerDictionary[containerName];
        }

        private static void ConfigureRootContainer(IUnityContainer container)
        {
            // Register Repositories mappings
            container.RegisterType<IClientesRepository, ClientesRepository>(new TransientLifetimeManager());
            container.RegisterType<ITiposDocumentosRepository, TiposDocumentosRepository>(new TransientLifetimeManager());
           
            // Register application services mappings
            container.RegisterType<IClientesManager, ClientesManager>(new TransientLifetimeManager());
            container.RegisterType<ITiposDocumentosManager, TiposDocumentosManager>(new TransientLifetimeManager());
          
        }

        private static void ConfigureRealContainer(IUnityContainer container)
        {
            container.RegisterType<IQueryableUnitOfWork, DemoArquitecturaEntities>(new PerExecutionContextLifetimeManager(), new InjectionConstructor());
            container.RegisterType<IMainModuleUnitOfWork, DemoArquitecturaEntities>(new PerExecutionContextLifetimeManager(), new InjectionConstructor());
            //container.RegisterType<IApplicationLogger, ApplicationLogger>(new TransientLifetimeManager());
        }

        #endregion
    }
}
